package sbu.cs;

import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import sbu.cs.asdb.ASDBUtils;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;

public class VircastDaemon extends Service {

	private Location currentBestLocation;

	private static final int TWO_MINUTES = 1000 * 60 * 2;

	protected static final String LOG_TAG = "VircastDaemon";

	private SharedPreferences sharedPrefs;
	private SharedPreferences.Editor editor;

	private LocationManager locationManager;
	
	private Date dbLastUpdated; 
	private LocationListener locationListener = new LocationListener() {

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onLocationChanged(Location location) {
			// TODO Auto-generated method stub
			//Log.i(LOG_TAG, "onLocationChanged: " + location.getLatitude() + " "
			//		+ location.getLongitude());
			if (currentBestLocation == null) {
				currentBestLocation = location;
			} else {
				if (isBetterLocation(location, currentBestLocation)) {
					Date curDate = new Date();
					currentBestLocation = location;

					double curLatitude = Settings.getPreferenceManager(null)
						.getLatitude();
					double curLongitude = Settings.getPreferenceManager(null)
						.getLongitude();
					
					float distanceResults[] = new float[3];
					Location.distanceBetween(curLatitude, curLongitude, location.getLatitude(),
							location.getLongitude(), distanceResults);
					editor.putString(Settings.KEY_LATITUDE,
							"" + currentBestLocation.getLatitude());
					editor.putString(Settings.KEY_LONGITUDE,
							"" + currentBestLocation.getLongitude());
					editor.commit();
					if(dbLastUpdated == null){
						dbLastUpdated = new Date();
						List<HashMap<String,String>> res = ASDBUtils.createASDBUtils().selectData();
						if(res == null){
							return;
						}
						String[] res_array = new String[res.size()];

						//int ix = 0;
						//for (Iterator i = res.iterator(); i.hasNext();) {
						//	res_array[ix++] = (String) i.next();
						//}

						if (res.size() > 0) {
							createNotification(res.size());
						}
						return;
					}
					//Log.i(LOG_TAG,"distance between current and old location: " + distanceResults[0]);
					//Log.i(LOG_TAG,"last update: " + (curDate.getTime() - dbLastUpdated.getTime()));
					if(distanceResults[0] > Settings.DISTANCE_DELTA || ((curDate.getTime() - dbLastUpdated.getTime())> Settings.DB_UPDATE_TIMEOUT)){
						List<HashMap<String,String>> res = ASDBUtils.createASDBUtils().selectData();
						if(res == null){
							return;
						}
						String[] res_array = new String[res.size()];

						//int ix = 0;
						//for (Iterator i = res.iterator(); i.hasNext();) {
						//	res_array[ix++] = (String) i.next();
						//}

						if (res.size() > 0) {
							createNotification(res.size());
						}
						dbLastUpdated = new Date();
					}
					
					//Log.i(LOG_TAG, "betterLocation: " + currentBestLocation.getLatitude() + " "
					//		+ currentBestLocation.getLongitude());

					// Toast t = Toast.makeText(getApplicationContext(), "betterLocation: " + currentBestLocation.getLatitude() + " "
					//		+ currentBestLocation.getLongitude(), Toast.LENGTH_SHORT);
					// t.show();
					// TODO DBUtil.query()
					// Gets all messages. Need to change
					
					
				}
			}
		}
	};

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.i(LOG_TAG, "onCreate");
		Settings.getPreferenceManager(getApplicationContext());
		locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		locationManager.requestLocationUpdates(
				LocationManager.GPS_PROVIDER, 0, 0, locationListener);
		sharedPrefs = PreferenceManager
				.getDefaultSharedPreferences(getBaseContext());
		editor = sharedPrefs.edit();
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		locationManager.removeUpdates(locationListener);
	}

	/**
	 * Determines whether one Location reading is better than the current
	 * Location fix
	 * 
	 * @param location
	 *            The new Location that you want to evaluate
	 * @param currentBestLocation
	 *            The current Location fix, to which you want to compare the new
	 *            one
	 */
	protected boolean isBetterLocation(Location location,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}

	private void createNotification(int num){
		String ns = Context.NOTIFICATION_SERVICE;
		NotificationManager notificationManager = (NotificationManager) getSystemService(ns);
		
		int icon = R.drawable.icon;
		CharSequence tickerText = "Vircast";
		long when = System.currentTimeMillis();

		Notification notification = new Notification(icon, tickerText, when);
		
		Context context = getApplicationContext();
		CharSequence contentTitle = "Vircast notification";
		CharSequence contentText = num + " vircasts at this location";
		Intent notificationIntent = new Intent(this, Main.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

		notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
		
		notificationManager.notify(Settings.NOTIFICATION_ID, notification);
	}
}
